package com.mytijian.runtime.executor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.mytijian.exception.BizSystemException;
import com.mytijian.runtime.RuntimeExceptionEnum;
import com.mytijian.runtime.model.param.AliCommonParam;

/**
 * 服务工作者，真正服务执行方法代理，包装真正服务方法
 * 目前只支持如下参数格式的方法
 * test(T t)
 * test(Object obj)
 * test(T t, Object obj)
 * test(Object obj, T t)
 * T 代表系统缺省请求参数，详情参考 @link{com.mytijian.runtime.model.param.AliCommonParam}
 * obj 代表服务定义的对象，和调用数据data（json格式）对应
 * @author Administrator
 *
 * @param <T>
 */
public class ServiceWorker {
	
	private Logger log = LoggerFactory.getLogger(ServiceWorker.class);

	private Object targetService;

	private Method method;

	public ServiceWorker(Method method, Object targetService) {
		this.method = method;
		this.targetService = targetService;
	}

	public <T extends AliCommonParam> Object execute(T param, String data) {
		return innerExecute(param, data);
	}

	private <T extends AliCommonParam> Object innerExecute(T param, String data) {
		try{
			return innerExecuteWithException(param, data);
		}catch(BizSystemException ex){
			log.error(ex.getMessage(), ex);
			throw ex;
		}
	}

	private <T extends AliCommonParam> Object innerExecuteWithException(T param, String data) {
		try {
			return method.invoke(targetService, getParamValues(param, data));
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new BizSystemException(RuntimeExceptionEnum.SERVICE_INVOKE_ERRO, e);
		} catch (InvocationTargetException e) {
			throw new BizSystemException(RuntimeExceptionEnum.SERVICE_INVOKE_ERRO, e.getTargetException());
		}
	}

	private <T extends AliCommonParam> Object[] getParamValues(T param, String data) {
		Parameter[] params = method.getParameters();
		Object[] paramValues = new Object[params.length];
		for (int i = 0; i < params.length; i++) {
			if (AliCommonParam.class.isAssignableFrom(params[i].getType())) {
				paramValues[i] = param;
			} else {
				if (data != null && data.length() > 0) {
					paramValues[i] = parseObject(data, params[i]);
				} else {
					paramValues[i] = null;
				}
			}
		}

		return paramValues;
	}

	private Object parseObject(String data, Parameter param) {
		try{
			return JSON.parseObject(data, param.getType());
		}catch(JSONException e){
			throw new BizSystemException(RuntimeExceptionEnum.DATA_PARSE_ERROR, e);
		}
	}

}
